/*
Project : Programmable Control of Airflow System for Maintaining Oxygen Saturation in Pre-term Infants
Microcontroller : STM32F4 Discovery (STM32F407VG)
File : Oxygen_Pulse_Meter.c
Function : Receive Data form Oxygen Pulse Meter such as Oxygen Saturation (SaO2)
Deverloper : Phattaradanai Kiratiwudhikul
Deverloped by Department of Electrical Engineering, Faculty of Engineering, Mahidol University
*/
//------------------------------------------------------------------------------
#include "main.h"
#include "driver_oxygen_pulse_meter.h"

#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"

#include <stdlib.h>
//------------------------------------------------------------------------------
// extern Variable
extern xQueueHandle *OPM_Queue;
extern xSemaphoreHandle  OPM_Semaphore;
//------------------------------------------------------------------------------                                              
//Variable store for Data input from Oxygen Pulse Meter, Buffer size 174 Bytes
char cDataFromOPM[SIZE_OF_OPM_BUFFER]; 
//------------------------------------------------------------------------------
uint8_t uiCurrent_SpO2;
uint8_t uiSD_Card_index = 0;
uint8_t uiRx_index_OPM = 0;
uint8_t uiOxygenSat_buffer[10];                                                 // Oxygen Saturation Buffer for Store Data to SD Card
//------------------------------------------------------------------------------
/*
  Function : Oxygen_PM_driver_setup
  Input : None
  Return : None
  Description : Setup driver for connecting Oxygen Pulse Meter with USART
*/
void oxygen_pulse_meter_driver_setup(void)
{
  //Set Up USART
  GPIO_InitTypeDef GPIO_InitStruct;
  USART_InitTypeDef USART_InitStruct;
	
  RCC_APB2PeriphClockCmd(OPM_USART_CLK, ENABLE);
  RCC_AHB1PeriphClockCmd(OPM_Port_CLK, ENABLE);
  /* Connect PXx to USARTx_Tx*/
  GPIO_PinAFConfig(OPM_Port, OPM_TX_Souce, OPM_TX_AF);
  /* Connect PXx to USARTx_Rx*/
  GPIO_PinAFConfig(OPM_Port, OPM_RX_Souce, OPM_RX_AF);
	
  /*
    Use Port A Pin PA2 to Tx
    Use Port A Pin PA3 to Rx
  */
  /* set GPIO init structure parameters values */
  GPIO_InitStruct.GPIO_Pin  = OPM_TX_Pin | OPM_RX_Pin;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(OPM_Port, &GPIO_InitStruct);
  
  /* USART_InitStruct members default value */
  USART_InitStruct.USART_BaudRate = 9600;
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;
  USART_InitStruct.USART_StopBits = USART_StopBits_1;
  USART_InitStruct.USART_Parity = USART_Parity_No ;
  USART_InitStruct.USART_Mode = USART_Mode_Rx;
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  USART_Init(OPM_USART, &USART_InitStruct);
  
  /*USART Interrupt*/
  /* Set interrupt: NVIC_Setup */
  //Data form Oxygen Pulse Meter : Priority 5
  NVIC_InitTypeDef NVIC_InitStruct;

  //ENABLE USART2 Interruper
  NVIC_InitStruct.NVIC_IRQChannel = OPM_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 5;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannel = ENABLE;
  NVIC_Init(&NVIC_InitStruct);

  /* Set Interrupt Mode*/
  //ENABLE the USART Receive Interrupt
  USART_ITConfig(OPM_USART, USART_IT_RXNE, ENABLE);
  //DISABLE the USART Transmit and Receive Interrupt
  USART_ITConfig(OPM_USART, USART_IT_TXE, DISABLE);
  
  //Disable OPM_USART (USART6)
  USART_Cmd(OPM_USART, DISABLE);

  //Set Up Timer 4
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  //Enable Clock Timer4
  RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, ENABLE);

  /* Enable the TIM4 gloabal Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
   
  /*
    Pre-Scale : APB1 Prescale 4
    System Clock 168MHz /4 = 42 MHz
    Timer Prescale 4200
  */
  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 5000;            
  TIM_TimeBaseStructure.TIM_Prescaler = 42000;                                  // 42 MHz Clock down to 1 kHz (adjust per your clock)
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  /* TIM IT enable */
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  /* TIM4 enable counter */
  TIM_Cmd(TIM4, DISABLE);
}

// USART_IRQHandler ------------------------------------------------------------
/*
  Function : OPM_IRQHandler
  Input : None
  Output : None
  Description : Interrupt Service Routine from OPM_USART
                Enable IT source : USART_IT_RXNE
*/
void OPM_IRQHandler(void)
{
  if(USART_GetITStatus(OPM_USART, USART_IT_RXNE) != RESET)
  {
    if (uiRx_index_OPM == 0)
    {
      //Start Receive Data from Oxygen Pulse Meter
      TIM_Cmd(TIM4, ENABLE);
    }
    cDataFromOPM[uiRx_index_OPM++] = USART_ReceiveData(OPM_USART);
  
    if(uiRx_index_OPM == (sizeof(cDataFromOPM)))
    {  
      TIM_Cmd(TIM4, DISABLE);
      TIM4->CNT = 0;                                                            // reset counter value in Timer 4
      uiRx_index_OPM = 0;
      
      /* Transfer data from ISR to Task */
      xQueueSend(OPM_Queue, &cDataFromOPM, portMAX_DELAY);                      // transfer data from Oxygen Pulse Meter to OPM task via OPM_Queue
      xSemaphoreGive(OPM_Semaphore);                                            // give semaphore for unblocking OPM_Task
    }
  }
  if(USART_GetITStatus(OPM_USART, USART_IT_TXE) != RESET)
  {
    USART_ITConfig(OPM_USART, USART_IT_TXE, DISABLE);                           // Disable Tx interrupt
    USART_ClearITPendingBit(OPM_USART, USART_IT_TXE);                           // clear flag Tx interrupt
  }
  
  USART_ClearITPendingBit(OPM_USART, USART_IT_RXNE);                            // clear flag Rx interrupt
}
//------------------------------------------------------------------------------
/*
  Function : Get_OxygenSat
  Input : char cData_from_OPM[]
  Return : (Struct) SDecode SCurrect_data_OPM
  Description : This Function is use for getting Oxygen Saturation Value (Percentage) from Oxygen Pulse Meter
                via RS-232 Oxygen Saturation Address = number 37 to 39 (start 0) (SpO2=099%)
*/

SDecode_data_OPM Get_OxygenSat(char cData_from_OPM[])
{
  /* define "SCurrect_data_OPM" structure for storing information that decode from Oxygen Pulse Meter */
  SDecode_data_OPM SCurrect_data_OPM;

  /* 
    This Function is use for getting Oxygen Saturation Value (Percentage) from Oxygen Pulse Meter via RS-232
    Oxygen Saturation Address = number 37 to 39 (start 0) (SpO2=099%)
  */
  char cOxygenSat_string[3];
  uint8_t uiOxygenSat_Percent, uiIndexString;
  uiOxygenSat_Percent = 0 ;

  /* check this command is getting SaO2 or Headding Command */
  if ((cData_from_OPM[18] == 'S') && (cData_from_OPM[19] == 'N') && (cData_from_OPM[126] == 'P') && (cData_from_OPM[127] == 'V') && (cData_from_OPM[128] == 'I'))
  {
    /* Case : Read Correct */
    for(uiIndexString = 0; uiIndexString < 3; uiIndexString++)
    {
      cOxygenSat_string[uiIndexString] = cData_from_OPM[37 + uiIndexString];
    }
    
    SCurrect_data_OPM.uiCurrent_SpO2 = atoi(cOxygenSat_string);                 // atoi is function convert from String to Int 

    /* Transfer data and time from Oxygen Pulse Meter to Buffer*/
    for (uint8_t uiIndexTime = 0; uiIndexTime < SIZE_DATE_TIME_BUFFER; uiIndexTime++)
    {
      SCurrect_data_OPM.cDateTime[uiIndexTime] = cData_from_OPM[uiIndexTime];
    }

    SCurrect_data_OPM.bReadCorrect = true;                                      // set ReadCorrect is true
  }
  else
  {
    /* Case :  Read Error */
    clear_OPM_buffer(cData_from_OPM);
    uiOxygenSat_Percent = '\0';
    SCurrect_data_OPM.uiCurrent_SpO2 = uiOxygenSat_Percent;
    SCurrect_data_OPM.bReadCorrect = false;                                     // Set ReadCorrect false
  }
  
  return SCurrect_data_OPM;
}
//------------------------------------------------------------------------------
/*
  Function : clear_OPM_buffer
  Input : char cData_clear
  Output : none
  Description : Clear data in data in Buffer in case of incorrect.
*/
void clear_OPM_buffer(char cData_clear[])
{
  uint8_t uiIndex_clear_buffer = 0;
  /*Clear data in Buffer*/
  for (uiIndex_clear_buffer = 0; uiIndex_clear_buffer < sizeof(cData_clear); uiIndex_clear_buffer++)
  {
    cData_clear[uiIndex_clear_buffer] = '\0';
  }
  uiRx_index_OPM = 0;
}
//------------------------------------------------------------------------------
/* 
  Function : TIM4_IRQHandler
  Input : None (Timer 4 Interrupt)
  Output : None
  Description : Timer 4 overflow of Receving data from Oxygen Pulse Meter ? 
                clear ucDataFromOPM buffer and reset uiRx_index_OPM.
*/
void TIM4_IRQHandler (void)
{
  if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
  {
    uint8_t uiRx_index_OPM = 0;
    //Clear Buffer Data from Oxygen Pulse Meter (OPM)
    for (uiRx_index_OPM = 0; uiRx_index_OPM < 133; uiRx_index_OPM++)
    {
      cDataFromOPM[uiRx_index_OPM] = '\0';
    }
    //Diable Timer4
    TIM_Cmd(TIM4, DISABLE);
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
  }
}
//------------------------------------------------------------------------------



// End of File -----------------------------------------------------------------
/*--------------------------------------------------------------------------------------------------
(C) Copyright 2014, Department of Electrical Engineering, Faculty of Engineering, Mahidol University
--------------------------------------------------------------------------------------------------*/
